<script setup lang="ts">
import { encryptPassword } from '@/utils/crypto';
import { getStorageItem, setStorageItem } from '@/utils/lf';
import { nanoid } from 'nanoid';
import { showFailToast, showSuccessToast, type FormInstance } from 'vant';
import { ref, toRaw } from 'vue';
import type { Password } from '../PassboxView.vue';
import { PASSWORD_ENUM } from '@/utils/constant';
import { iconMap } from '@/components/icons/iconmap';
import { OnLongPress } from "@vueuse/components"


const props = defineProps<{
  mode: 'create' | 'edit',
  id?: string
}>();

const emit = defineEmits<{
  (e: 'update:showPopup', value: boolean): void
  (e: 'update:passwordList'): void
}>();

export interface PasswordFragment {
  id: string;
  value: string;
  closeable: boolean;
}

const passwordInit = {
  title: '',
  account: '',
  password: '',
  logo: 'unknown'
}
const passTpye = ref('input');
const account = ref({ ...passwordInit })
const passwordForm = ref<FormInstance>();
const passwordList = ref<Password[]>([])
// 密码片段列表
const fragmentsList = ref<PasswordFragment[]>([])
// 常见账户图标
const logos = Object.entries(iconMap);
const checkedLogoName = ref<string>('unknown')
const localShow = ref(false);
const fragment = ref('')
const accountWillBeEdited = ref<Password>()

const saveAccount = async () => {
  try {
    await passwordForm.value?.validate();
    const savedData = { id: nanoid(), ...account.value, password: encryptPassword(account.value.password), logo: checkedLogoName.value }
    const existedPasswords = await getStorageItem(PASSWORD_ENUM.LIST_KEY) as Password[];
    if (existedPasswords) {
      const newPasswords = [...existedPasswords, savedData];
      await setStorageItem(PASSWORD_ENUM.LIST_KEY, newPasswords);
      passwordList.value = newPasswords as Password[];
    } else {
      await setStorageItem(PASSWORD_ENUM.LIST_KEY, [savedData]);
      passwordList.value = [{ ...savedData }] as Password[];
    }

    account.value = { ...passwordInit };
    localShow.value = false;
    showSuccessToast('保存成功');
    emit('update:passwordList');
  } catch {
    showFailToast('表单信息填写不完整, 请检查后在提交');
  }
}

const saveEdit = async () => {
  try {
    // 校验编辑表单, 密码非必填
    await passwordForm.value?.validate();
    const editedPassword = account.value.password;
    const editedData = {
      ...account.value,
      logo: checkedLogoName.value
    }
    editedData.password = editedPassword ? encryptPassword(editedPassword) : accountWillBeEdited.value!.password;
    const existedAccounts = await getStorageItem(PASSWORD_ENUM.LIST_KEY) as Password[];
    const targetAccountIndex = existedAccounts.findIndex(item => item.id === props.id);
    existedAccounts[targetAccountIndex] = editedData as Password;

    await setStorageItem(PASSWORD_ENUM.LIST_KEY, existedAccounts);
    localShow.value = false;
    showSuccessToast('修改成功');
    emit('update:passwordList');
  } catch {
    showFailToast('表单信息填写不完整, 请检查后在提交');
  }
};

const initData = async () => {
  // 获取密码片段列表
  const passwordFragments = await getStorageItem(PASSWORD_ENUM.PASSWORD_FRAGMENT_KEY) as PasswordFragment[]
  fragmentsList.value = passwordFragments || [];
}

const addFragment = () => {
  if (!fragment.value) {
    showFailToast('请输入密码片段内容');
    return;
  }
  fragmentsList.value.push({ id: nanoid(), value: fragment.value, closeable: false });
  // 需要转换为原始对象,不然 indexdb 会报错
  setStorageItem(PASSWORD_ENUM.PASSWORD_FRAGMENT_KEY, toRaw(fragmentsList.value));
  fragment.value = '';
}

const setPassword = (value: string) => {
  account.value.password += value
}

const onLongPressCallbackComponent = (e: PointerEvent, fragment: PasswordFragment) => {
  e.preventDefault();
  fragment.closeable = true;
  console.log('on long pressed')
}

const closeFragment = (id: string) => {
  const idx = fragmentsList.value.findIndex(item => item.id === id);
  fragmentsList.value.splice(idx, 1);
  setStorageItem(PASSWORD_ENUM.PASSWORD_FRAGMENT_KEY, toRaw(fragmentsList.value));
}

defineExpose({
  showCreatePopup: async () => { localShow.value = true; initData(); },
  showEditPopup: async () => {
    initData();
    localShow.value = true;
    // 编辑密码
    if (props.id) {
      const list = await getStorageItem(PASSWORD_ENUM.LIST_KEY) as Password[]
      accountWillBeEdited.value = list.find(item => item.id === props.id)!;
      checkedLogoName.value = accountWillBeEdited.value.logo;
      account.value = { ...accountWillBeEdited.value };
      account.value.password = ''
    }
  }
})
</script>

<template>
  <van-popup v-model:show="localShow" position="bottom" teleport="body" :style="{ height: '80%' }" :round="true">
    <div class="bg-neutral-50 dark:bg-neutral-800 pt-4 h-full">

      <h4 class="text-center mb-4 text-xl font-bold">{{ mode === 'create' ? '新建' : '编辑' }}账户信息</h4>
      <van-form ref="passwordForm" :show-error-message="false">
        <van-cell-group inset>
          <van-field label-width="80" v-model="account.title" label="账号名称" name="title"
            :rules="[{ required: true, message: '请填写账号名称' }]" />
          <van-field label-width="80" v-model="account.account" label="账号" name="account"
            :rules="[{ required: true, message: '请填写账号' }]" />
          <van-field name="radio" label="密码来源">
            <template #input>
              <van-radio-group v-model="passTpye" direction="horizontal">
                <van-radio name="input">输入密码</van-radio>
                <van-radio name="fragment">密码片段</van-radio>
              </van-radio-group>
            </template>
          </van-field>
          <van-field label-width="80" v-model="account.password" :type="passTpye === 'input' ? 'password' : 'text'"
            label="密码" :rules="[{ required: mode === 'create', message: '请填写密码' }]" :disabled="passTpye === 'fragment'">
            <template #button>
              <van-button v-if="passTpye !== 'input'" size="small" type="danger" @click="account.password = ''"
                :disabled="!account.password">重置密码</van-button>
            </template>
          </van-field>
        </van-cell-group>
      </van-form>

      <div>
        <h4 class="text-center my-4 text-xl font-bold">密码片段</h4>
        <div class="pass-fragments mx-3 flex flex-wrap gap-2 mb-2">
          <OnLongPress as="button" class="ml-2 button small" @trigger="(e) => onLongPressCallbackComponent(e, fragment)"
            v-for="(fragment, index) in fragmentsList" :key="index">
            <van-tag plain size="large" type="primary" @click="setPassword(fragment.value)"
              :closeable="fragment.closeable" @close="closeFragment(fragment.id)">
              <span class="select-none">{{ fragment.value }}</span>
            </van-tag>
          </OnLongPress>
        </div>

        <van-cell-group inset>
          <van-field v-model="fragment" center clearable label="密码片段" placeholder="请输入密码片段"
            :disabled="passTpye !== 'fragment'">
            <template #button>
              <van-button size="small" type="primary" @click="addFragment"
                :disabled="passTpye === 'input'">添加片段</van-button>
            </template>
          </van-field>
        </van-cell-group>
      </div>

      <h4 class="text-center my-4 text-xl font-bold">图标</h4>
      <div class="logos mx-6 flex items-center gap-2">
        <div class="relative" v-for="([name, cmp], index) in logos" :key="index">
          <component @click="checkedLogoName = name" :is="cmp" class="w-12 h-12" />
          <CheckedIcon v-if="name === checkedLogoName" class="w-3 h-3 absolute right-0 top-0" />
        </div>
      </div>
      <div class="px-4 mt-8">
        <van-button v-if="mode === 'create'" type="primary" round block @click="saveAccount">保存</van-button>
        <van-button v-if="mode === 'edit'" type="primary" round block @click="saveEdit">保存修改</van-button>
      </div>
    </div>
  </van-popup>
</template>

<style lang="scss" scoped></style>
